QuerySet对象说明


  • QuerySet是Django中的一个特殊对象,本质上了列表是一样的,也可以将它理解为列表
  • QuerySet的本质是继承了 list 类

打印SQL语句


  • 方法一 -> 在settings.py中进行配置(在配置文件章节中有提到)

  • 方法二 -> 指定打印那个orm的SQL语句

    • .query

data = Student.objects.all()

sql = data.query

print(sql)  # SELECT "app01_student"."id", "app01_student"."name", "app01_student"."age", "app01_student"."classes_id" FROM "app01_student"

添加数据


  • 写法一

# 表的类.objects.create(字段名=xxx, 字段名=xxx)

Student.objects.create(username='Yeung')

  • 写法二

obj = Student(username='Kevin')
obj.save()

# 或者简写

Student(username='Kevin').save()

  • 写法三

dic = {'username': 'Kevin'}

Student.objects.create(**dic)

  • 批量添加数据

表的类.objects.bulk_create(对象列表num) -> num: 每次以num条写入数据库

class_lis = [
    Classes(name='班级一'),
    Classes(name='班级二'),
    Classes(name='班级三'),
    Classes(name='班级四'),
]

# class_lis = [Classes(name='班级{}'.format(i)) for i in range(100)]

Classes.objects.bulk_create(class_lis, 10)

  • DateField()、DatetimeField()、TimeField() 字段类

    • 日期字段类可以保存 字符串的日期(前提: 日期字段没有设置 auto_now_add=True) 或 日期对象(即: datetime)

    • 如果日期字段保存的是字符串,那么取出来的也是字符串的日期(前提: 日期字段没有设置 auto_now_add=True,如果设置了 auto_now_add=True 那么保存的则是当前时间的日期对象,而不是你所指定的字符串的日期)

    • 如果日期字段保存的是日期对象,那么取出来的也是日期对象

    • 虽然可以保存字符串的日期,但是还是推荐保存日期对象

# model.py

class Book(models.Model):
    title = models.CharField(max_length=15, verbose_name='书名')
    price = models.IntegerField(verbose_name='价格')
publish_date = models.DateField(auto_now_add=False, verbose_name='出版日期')

# 保存的是字符串时间

obj = Book.objects.create(title='三国演义', price=100, publish_date='2018-9-1')
print(obj.publish_date, type(obj.publish_date))  # 2018-9-1 <class 'str'>

# 保存的是字符串时间,但日期字段设置了 auto_now_add=True

obj = Book.objects.create(title='三国演义', price=100, publish_date='2018-9-1')
print(obj.publish_date, type(obj.publish_date))  # 2019-06-18 <class 'datetime.date'>

# 保存的是日期对象

import datetime

obj = Book.objects.create(title='水浒装', price=50, publish_date=datetime.datetime.now())
print(obj.publish_date, type(obj.publish_date))  # 2019-06-18 15:26:34.999867 <class 'datetime.datetime'>

  • FileField 或 ImageField 字段类

    • 通过 FileField 或 ImageField 字段类所创建的字段,在添加数据的时候该字段一般接受一个文件对象

    • 通过 FileField 或 ImageField 字段类所创建的字段接受到一个文件对象的时候,会将文件保存到 upload_to 字段属性所设置的文件夹路径下,如果配置了 media 那么文件就会保存到 media 目录下,然后将保存后的文件路径写入到该字段下

      • upload_to 的相关说明:
        • 如果设置了 upload_to 字段属性 和 配置了 media,那么文件就会保存在 media 目录下的 upload_to 字段属性所设置的文件夹路径里
        • 如果设置了 upload_to 字段属性,没有配置 media,那么文件就会保存在 upload_to 字段属性所设置的文件夹路径里
        • 如果没有设置了 upload_to 字段属性,但配置了 media,那么文件就会保存在 media 目录下
        • 如果没有设置了 upload_to 字段属性,也没有配置了 media,那么文件就会保存项目根目录下

    • 当 FileField 或 ImageField 字段类中设置了默认值得前提下,如果该字段接受到的不是一个文件对象而是一个None的话,那么该字段的数据不会保存 FileField 或 ImageField 字段类中所设置的默认值,而是保存一个空(即: NULL),如果想使用默认值那么就不要对该字段传任何数据

    • 普通情况下的添加图片或文件数据

# models.py

class Picture(models.Model):
    title = models.CharField(max_length=32, verbose_name='标题')
    img = models.ImageField(upload_to='img/', verbose_name='图片')

# views.py

from app01.models import *
from django.shortcuts import render
import time


def home(request):
    if request.method == 'POST':
        img = request.FILES.get('img')
        if img:
# 修改文件名,以时间作为文件名
            img_name = img.name  # 获取上传文件的文件名+后缀名
            suffix = img_name.rsplit('.', 1)[1]  # 获取文件后缀名
            time_name = time.strftime("%Y%m%d%H%M%S")
            img.name = '%s.%s' % (time_name, suffix)

            Picture.objects.create(title='Kevin', img=img)  # 将文件对象传递给 FileField 或 ImageField 字段

    return render(request, 'home.html')

    • 创建 admin 用户添加头像

# models.py

class UserInfo(AbstractUser):
    avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png")

# views.py

def register(request):
    if request.method == 'POST':
        file_obj = request.FILES.get('avatar')  # 接受一个文件对象
        if file_obj:  # 判断是否是一个文件对象
            # avatar 字段是通过 FileField 或 ImageField 字段类所创建的
            UserInfo.objects.create_user(avatar=file_obj, username='Kevin', password='123')  # 将文件对象传递给 avatar 字段
        else:
            UserInfo.objects.create_user(username='Kevin', password='123')  # 如果 file_obj 不是一个文件对象,那么不对 avatar 字段做任何操作,让 avatar 字段使用默认值
    return render(request, 'register.html')

  • .update_or_create()

    • 判断某条数据是否存在,如果存在就对该条数据进行修改,如果不存在就进行添加(即: 如果有该条数据就进行修改,没有就添加)

    • 语法: .update_or_create(字段名A=xxx, defaults={字段名: xxx, 字段名: xxx, ……})

      • 以 字段名A + 字段名A的内容 作为查询条件,查询是否有该条数据,如果有就将该条数据中的值修改为 defaults 字典中对应的值,如果没有就添加该条数据

from api.models import *
import datetime
import uuid

user = UserInfo.objects.filter(username='Kevin', password='123').first()
uid = str(uuid.uuid4())

UserToken.objects.update_or_create(user=user, defaults={'token': uid, 'created': datetime.datetime.now()})
"""
    代码解释:
        1. 判断token表中是否存在 user字段等于user对象 的这条数据
        2. 如果有: 就将该条数据中的 token 字段和 created 字段修改为 defaults 参数中所对应的值
        3. 如果没有: 就在 token 表中添加一条数据(即:user字段等于user对象,token字段和 created字段 等于 defaults 参数中所对应的值)
"""

删除数据


  • 先查询到要删除的数据(返回值: 对象),然后通过对象删除数据

# 查询到的对象.delete()

obj = Student.objects.get(id=2)
obj.delete()

# 或者简写

Student.objects.get(id=2).delete()

  • 批量删除数据,即: 使用 filter() 查询数据(返回值: QuerySet->列表),然后对数据进行删除

    • 方法一: 直接使用 .delete() 方法,对查询到的进行删除 -> 推荐使用

Student.objects.filter(age=18).delete()

    • 方法二: 循环返回的QuerySet,获取到QuerySet中的对象然后再进行删除

objs = Student.objects.filter(age=18)
for i in objs:
    i.delete()

修改数据


  • 先查询到要修改的数据(返回值: 对象),然后通过对象修改数据

# 查询到的对象.字段名 = xxx
# 查询到的对象.save()

obj = Student.objects.get(id=1)
obj.username = 'Yeung'
obj.save()

  • 批量修改数据,即:使用 filter() 查询数据(返回值: QuerySet->列表),然后对数据进行修改

    • 方法一: 使用 .update(字段名=xxx, 字段名=xxx) -> 推荐使用

objs = Student.objects.filter(id=4)
objs.update(username='Aimer')

# 或者简写

Student.objects.filter(id=4).update(username='Aimer')

    • 方法二: 循环返回的QuerySet,获取到QuerySet中的对象然后再进行修改

objs = Student.objects.filter(id=1)

for i in objs:
    i.username = 'Yeung'
    i.save()

  • FileField 或 ImageField 字段类

    • 通过 FileField 或 ImageField 字段类所创建的字段接受到一个文件对象的时候,会将文件保存到 upload_to 字段属性所设置的文件夹路径下,如果配置了 media 那么文件就会保存到 media 目录下,然后将保存后的文件路径写入到该字段下

      • upload_to 的相关说明:
        • 如果设置了 upload_to 字段属性 和 配置了 media,那么文件就会保存在 media 目录下的 upload_to 字段属性所设置的文件夹路径里
        • 如果设置了 upload_to 字段属性,没有配置 media,那么文件就会保存在 upload_to 字段属性所设置的文件夹路径里
        • 如果没有设置了 upload_to 字段属性,但配置了 media,那么文件就会保存在 media 目录下
        • 如果没有设置了 upload_to 字段属性,也没有配置了 media,那么文件就会保存项目根目录下

    • 当 FileField 或 ImageField 字段类中设置了默认值得前提下,如果该字段接受到的不是一个文件对象而是一个None的话,那么该字段的数据不会保存 FileField 或 ImageField 字段类中所设置的默认值,而是保存一个空(即: NULL),如果想使用默认值那么就不要对该字段传任何数据

    • 使用 .FileField/ImageField字段对象.save(文件名, 文件对象) 修改文件

# models.py

class Picture(models.Model):
    title = models.CharField(max_length=32, verbose_name='标题')
    img = models.ImageField(upload_to='img/', verbose_name='图片')

# views.py

import os
import time
from app01.models import *
from django.conf import settings
from django.shortcuts import render


def home(request):
    if request.method == 'POST':
        picture_obj = Picture.objects.all().first()
        img = request.FILES.get('img')
        if img:
            old_img_path = picture_obj.img.name

# 修改文件/图片
            img_name = img.name  # 获取上传文件的文件名+后缀名
            suffix = img_name.rsplit('.', 1)[1]  # 获取文件后缀名
            time_name = time.strftime("%Y%m%d%H%M%S")
            new_img_name = '%s.%s' % (time_name, suffix)
            picture_obj.img.save(new_img_name, img)
            picture_obj.save()

# 删除旧文件/图片
            old_img_path_list = old_img_path.split('/')
            old_img_address = os.path.join(settings.BASE_DIR, 'media', *old_img_path_list)
            os.remove(old_img_address)

    return render(request, 'home.html')

查询数据


1. filter() 方法支持 filter(表名__字段名的写法) 详细请查看 ORM-跨多张表查询自身的数据

2.pk 参数

  • 在每一个查询出来的数据对象(即: QuerySet里面的每一个数据对象)中都会包含一个 pk 参数

  • pk 参数: 代指的就是主键(即: id)

  • 使用场景: 

    • 有时候我们的主键不是id而是 nid, pid, tid 等,这时候就可以直接通过 .pk 获取到该条数据的主键是什么

    • 在模板语言中也可以使用该参数

# views.py

# 用法一

student_list = Student.objects.all()

for student in student_list:
    pk_id = student.pk
    print(pk_id)  # 1

# 用法二

student_id = Student.objects.get(name='Kevin').pk  # 2

# 用法三

student_obj = Student.objects.filter(pk=1).first()

# 用法四

student_list = Student.objects.all().values('pk', 'name')

# xxx.html

<p> {{ obj.pk }} </p>

3.查询某个字段为空的数据

  • 字段名=None 就是查询该字段为空的数据

Student.objects.filter(age=18, address=None)

4.查询该表的所有数据

  • 方式一: .all()

# 表的类.objects.all()

Student.objects.all()  # 返回值:QuerySet -> 列表 -> <QuerySet [<Student: Student object>, <Student: Student object>]>

  • 方式二: ** 动态实参

field_data = {}

Student.objects.filter(**field_data)  # 返回值:QuerySet -> 列表 -> <QuerySet [<Student: Student object>, <Student: Student object>]>

  • 通过循环返回值获取查询到的数据

# 通过 对象.字段名 获取查询到的数据

objs = Student.objects.all()

for i in objs:
    print(i.id, i.username)

5..filter() -> 通过条件查询一堆数据

# 表的类.objects.filter(条件)

Student.objects.filter(age=18)  # 返回值:QuerySet -> 列表 -> <QuerySet [<Student: Student object>, <Student: Student object>]>

  • 通过循环返回值获取查询到的数据

# 通过 对象.字段名 获取查询到的数据

objs = Student.objects.filter(age=18)

for i in objs:
    print(i.id, i.username)

6..get() -> 通过条件查询一条数据,没有查询到 或 查询到多条数据就会报错

# 表的类.objects.get(条件)

Student.objects.get(id=1)  # 返回值: 对象 -> <Student: Student object> 

  • 通过 对象.字段名 获取查询到的数据

# 通过 对象.字段名 获取查询到的数据

obj = Student.objects.get(id=1)

print(obj.id, obj.username)

7..exclude() -> 查询与该条件不符的数据(通俗理解: .filter() 方法取反)

# 表的类.objects.exclude(条件)

Student.objects.exclude(id=2)  # 返回值:QuerySet -> 列表 -> <QuerySet [<Student: Student object>, <Student: Student object>]>

  • 通过循环返回值获取查询到的数据

# 通过 对象.字段名 获取查询到的数据

objs = Student.objects.exclude(id=2)

for i in objs:
    print(i.id, i.username)

8..values('字段名','字段名') -> 只取某几列的数据

  • 只取某几个字段的数据(通俗理解: 只取某几列的数据)
  • .all() 和 .filter() 都可以使用 .values()
  • .values() 不传任何字段名,默认获取全部字段
  • 返回值: QuerySet -> 列表,且QuerySet中的值是以字典(键值对)的形式显示

# 表的类.objects.all().values('字段名', '字段名')

Student.objects.all().values('username','age')  # 只取 username 字段 和 age 字段的数据
                                                # 返回值:QuerySet -> 列表 -> <QuerySet [{'username': 'Yeung', 'age': 23}, {'username': 'Kevin', 'age': 18}, {'username': 'Eric', 'age': 22}]>

# .values() 不传任何字段名,默认获取全部字段

Student.objects.all().values()

9..values_list('字段名', '字段名') -> 只取某几列的数据

  • 只取某几个字段的数据(通俗理解: 只取某几列的数据)
  • .all() 和 .filter() 都可以使用 .values_list()
  • .values_list() 不传任何字段名,默认获取全部字段
  • 返回值: QuerySet -> 列表,且QuerySet中的值是以元祖的形式显示
  • 和 values 的区别: values_list 直接返回查询到的数据且不带key,而 values 返回查询到的数据带key

# 表的类.objects.all().values_list('字段名', '字段名')

Student.objects.all().values_list('username','age')  # 只取 username 字段 和 age 字段的数据
                                                     # 返回值:QuerySet -> 列表 -> <QuerySet [('Yeung', 23), ('Kevin', 18), ('Eric', 22)]>

# .values_list() 不传任何字段名,默认获取全部字段

Student.objects.all().values_list()

10..only('字段名', '字段名')-> 只取某几列的数据

  • 只取某几个字段的数据(通俗理解: 只取某几列的数据)
  • .all() 和 .filter() 都可以使用 .only()
  • .only() 不传任何字段名,默认获取全部字段
  • 返回值: QuerySet -> 列表,且QuerySet中的值是以对象的形式显示
  • 和 values 的区别: only 所返回的值(queryset 中的值是对象,而 value 所返回的值(queryset 中的值是字典

# 表的类.objects.all().only('字段名', '字段名')

student_list = Student.objects.all().only('username', 'age')  # 只取 username 字段 和 age 字段的数据
print(student_list)  # <QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>]>

for student in student_list:
    print(student.__dict__)  # {'id': 1, 'username': 'Kevin', 'age': 18, '_state': <django.db.models.base.ModelState object at 0x000002608AE065F8>}
    print(student.username)  # Kevin
    print(student.age)  # 18
    print(student.address)  # 横沥 -> 注意: 可以获取不是only指定的列的数据,但是不建议这样去操作,因为会增加多一次SQL查询(详细说明: student_list 获取到的是包含 username 和 age 字段的数据,如果要获取 address 字段的数据,那么django就会通过当前行的id去查询address字段的数据,这样就会增加了一次SQL查询,如果 student_list 有500条数据,在循环的时候都要获取address字段的数据,那么就会增加了500次SQL查询)

11..defer('字段名', '字段名')-> 获取不是这几列的数据,即 only 取反

  • 不取这几个字段的数据(通俗理解: 获取不是这几列的数据)
  • .all() 和 .filter() 都可以使用 .defer()
  • .defer() 不传任何字段名,默认获取全部字段
  • 返回值: QuerySet -> 列表,且QuerySet中的值是以对象的形式显示
  • 和 only 的区别: defer 就是 only 的取反
  • 和 values 的区别: defer 所返回的值(queryset 中的值是对象,而 value 所返回的值(queryset 中的值是字典

# 表的类.objects.all().defer('字段名', '字段名')

student_list = Student.objects.all().defer('age', 'address')  # 不取 age 字段 和 address 字段的数据
print(student_list)  # <QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>]>

for student in student_list:
    print(student.__dict__)  # {'id': 1, 'username': 'Kevin', '_state': <django.db.models.base.ModelState object at 0x00000222907B65C0>}
    print(student.username)  # Kevin
    print(student.address)  # 横沥 -> 注意事项和only一样这里就不做说明了

12..order_by() -> 对查询的结果进行排序

  • .order_by() -> 不传任何参数,默认会按照元信息中的 ordering 所设置的字段排序,如果元信息中的 ordering 属性,那么就按照id排序

  • 正序 -> .order_by() 默认正序排序

    • 查询所有数据然后进行正序排序

# 表的类.objects.order_by('字段名')

Student.objects.order_by('age')  # 返回值:<QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>]> 
                                 # 通过循环,以 对象.字段名 的形式获取查询到的值,上面 .all()/.filter() 有举例,这里就不演示

# 等价于

Student.objects.all().order_by('age')

    • 对查询的结果进行正序排序

# 表的类.objects.all/filter/exclude(条件).order_by('字段名')

Student.objects.filter(id__gt=1).order_by('age')  # 查询 id 大于 1 的数据,然后进行正序排序

  • 倒序

    • 查询所有数据然后进行倒序排序

# 表的类.objects.order_by('-字段名')

Student.objects.order_by('-age')

# 等价于

Student.objects.all().order_by('-age')

    • 对查询的结果进行倒序排序

# 表的类.objects.all/filter/exclude(条件).order_by('-字段名')

Student.objects.filter(id__gt=1).order_by('-age')  # 查询 id 大于 1 的数据,然后进行倒序排序

  • .order_by() 的第二个字段名参数,如果数据相同就以第二个字段参数进行二次排序

# 表的类.objects.order_by('字段名', '字段名')

Student.objects.order_by('age','-id')

# 表的类.objects.all/filter/exclude(条件).order_by('字段名', '字段名')

Student.objects.filter(id__gt=1).order_by('age','-id')

13..reverse() -> 对查询的数据进行反转排序

  • 对查询的数据进行反转排序

  • 注意:
    • .reverse() 只能对有序的QuerySet对象进行反转
    • 有序的QuerySet的意思是对查询出来的结果进行过排序的QuerySet对象
    • 不对查询结果进行排序的,一般返回的都是无序的 QuerySet对象,除非在创建表时设置元信息中的ordering属性(默认对查询出来的结果进行排序)

  • 使 .reverse() 生效的方法:
    • 对查询结果进行一次排序,且 .order_by() 里面必须传字段名,否则 .reverse() 会无效
    • 在创建表时设置元信息中ordering,默认对查询出来的结果进行排序 -> 不建议使用

  • 通俗理解上面所说的意思: 一定要对查询结果进行一次排序,且 .order_by() 里面必须传字段名,否则 .reverse() 会无效

# 表的类.objects.all/filter/exclude(条件).order_by('字段名').reverse()

Student.objects.all().order_by('id').reverse()  # 返回值: <QuerySet [<Student: Student object>, <Student: Student object>, <Student: Student object>]>

14..distinct() -> 对查询的结果进行过滤剔除重复的数据

  • 对查询的结果进行过滤剔除重复的数据
  • 注意: 只要有一个字段中的数据不同(如: id)都会无效

Student.objects.values('username','address').distinct()  # <QuerySet [{'address': '横沥', 'username': 'Yeung'}, {'address': '东莞', 'username': 'Kevin'}, {'address': '广东', 'username': 'Eric'}]>

15..count() -> 获取查询到的数据的总数

Student.objects.all().count()  # 4

16..first() -> 返回查询到的数据中的第一条记录

Student.objects.all().first()  # 返回值: 对象 -> <Student: Student object>

17..last() -> 返回查询到的数据中的最后一条记录

Student.objects.all().last()  # 返回值: 对象 -> <Student: Student object>

18..exists() -> 判断是否查询到数据(通俗理解: 判断返回的QuerySet或对象中是否有值), 如果有返回 True,否则返回 False

Student.objects.all().exists()  # True

Student.objects.filter(id=10).exists()  # False

19..get_设置了choices参数的字段名_dispaly() ->  获取 choices 参数中 索引为1 的值

  • 一般直接获取设置了 choices 参数的字段中的值的时候,只会获取 choices 参数中 索引为0 的值(因为数据库保存的就是这个值),通过 .get_设置了choices参数的字段名_dispaly() 方法可以获取 choices 参数中 索引为1 的值

  • 在模板语言中也可以使用该方法只要把 () 去掉即可

# models.py

class ChoicesTable(models.Model):
    education_choices = (
        (1, '重点大学'),
        (2, '普通本科'),
        (3, '独立院校'),
        (4, '民办本科'),
        (5, '大专'),
        (6, '民办专科'),
        (7, '高中'),
        (8, '其他')
    )
    education = models.IntegerField(verbose_name='学历', choices=education_choices, default=1)

    record_choices = (
        ('checked', "已签到"),
        ('vacate', "请假"),
        ('late', "迟到"),
        ('noshow', "缺勤"),
        ('leave_early', "早退"),
    )
    record = models.CharField(verbose_name="上课纪录", choices=record_choices, default="checked", max_length=64)

data = ChoicesTable.objects.all().first()

education = data.education  # 1 -> 直接获取只会获取到 choices 参数中 索引为0 的值
education = data.get_education_display()  # 重点大学 -> 获取 choices 参数中 索引为1 的值

record = data.record  # checked -> 直接获取只会获取到 choices 参数中 索引为0 的值
record = data.get_record_display()  # 已签到 -> 获取 choices 参数中 索引为1 的值

20. 切片

  • 可以对查询到的数据进行切片,前提是该数据是 QuerySet->列表 类型,而不是对象

  • 切片的时候不能使用负数,否则会报错

data = Student.objects.all()[1:3]

21.查询数据的分类

返回值类型方法名
QuerySet对象
(列表中的值是对象)
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet对象
(列表中的值是字典类型)
values() 
特殊的QuerySet对象
(列表中的值是元祖类型)
values_list()
对象
get()
first()
last()
布尔值
exists()
数字
count()

条件查询


1. 等于、不等于

# 查询 id 等于 2 的数据

Student.objects.filter(id=2)

# 等于

Student.objects.filter(id__exact=2)

# 查询 id 不等于 2 的数据

Student.objects.exclude(id=2)

2. 大于、大于等于

  • 字段名__gt -> 大于 >

# 查询 id 大于 1 的数据 

Student.objects.filter(id__gt=1)

  • 字段名__gte -> 大于等于 >=

# 查询 id 大于等于 2 的数据

Student.objects.filter(id__gte=2)

3. 小于、小于等于

  • 字段名__lt -> 小于 <

# 查询 id 小于 3 的数据

Student.objects.filter(id__lt=3)

  • 字段名__lte -> 小于等于 <=

# 查询 id 小于等于 2 的数据

Student.objects.filter(id__lte=2)

4. in / not in

  • 字段名__in = [xxx,xxx,xxx] -> 等同于MySQL里的 in ->  查询xxx在这堆数据里的数据

# 查询 id 在 [2, 4] 里的数据

Student.objects.filter(id__in=[2, 4])

  • not in -> 使用 .exclude() 查询数据的方法实现Mysql中的 not in

# 查询 id 不在 [2, 4] 里的数据

Student.objects.exclude(id__in=[2, 4])

5. between

  • 字段名__range = [num, num] -> 查询xxx字段在这个范围里的数据

# 查询 id 在 2~4 这个范围的数据

Student.objects.filter(id__range=[2, 4])

6. like 模糊查询

  • 字段名__contains

    • 查询xxx字段中包含 xxx 的数据
    • 等同于 MySQL 中的 like '%ev%'

# 查询username字段中包含 'ev' 的数据

Student.objects.filter(username__contains='ev')

  • 字段名__icontains

    • 查询xxx字段中包含 xxx 的数据
    • 不区分大小写

# 查询username字段中包含 'ev' 的数据,不区分大小写

Student.objects.filter(username__icontains='ev')

  • 字段名__exact 

    • 查询xxx字段中等于 xxx 的数据
    • 精准查询
    • 等同于 MySQL 中的 like 'Eric'

# 查询username字段中等于 'Eric' 的数据

Student.objects.filter(username__exact='Eric')

# 等同于

Student.objects.filter(username='Eric')

  • 字段名__iexact

    • 查询xxx字段中等于 xxx 的数据
    • 精准查询,不区分大小写

# 查询username字段中等于 'Eric' 的数据,不区分大小写

Student.objects.filter(username__iexact='eric')

  • 字段名__startswith

    • 查询 xxx 字段以 xxx 开头的数据
    • 等同于 MySQL 中的 like 'Er%'

# 查询username字段中以 'Er' 开头的数据

Student.objects.filter(username__startswith='Er')

  • 字段名__istartswith

    • 查询 xxx 字段以 xxx 开头的数据
    • 不区分大小写

# 查询username字段中以 'Er' 开头的数据,不区分大小写

Student.objects.filter(username__istartswith='er')

  • 字段名__endswith

    • 查询 xxx 字段以 xxx 结尾的数据
    • 等同于 MySQL 中的 like '%ic'

# 查询username字段中以 'ic' 结尾的数据

Student.objects.filter(username__endswith='ic')

  • 字段名__iendswith

    • 查询 xxx 字段以 xxx 结尾的数据
    • 不区分大小写

# 查询username字段中以 'ic' 结尾的数据,不区分大小写

Student.objects.filter(username__iendswith='IC')

  • 字段名__year -> 查询日期字段中某一年的数据

# 查询2019年的数据

Student.objects.filter(datetime__year=2019)

# 查询 2017~2019 年的数据 -> 直接在 __year 后面拼接上 __range 范围查询就可以了

Student.objects.filter(datetime__year__range=[2017, 2019])

  • 字段名__month -> 查询日期字段中某个月的数据

# 查询4月的数据

Student.objects.filter(datetime__month=4)

# 查询 2月 ~ 4月 的数据 -> 直接在 __year 后面拼接上 __range 范围查询就可以了

Student.objects.filter(datetime__month__range=[2, 4])

  • 字段名__day -> 查询日期字段中某一日的数据

# 查询日期为2号的数据

Student.objects.filter(datetime__day=2)

# 查询日期 1号 ~ 4号 的数据 -> 直接在 __year 后面拼接上 __range 范围查询就可以了

Student.objects.filter(datetime__day__range=[1, 4])

7. is null / is not null

  • 字段名__isnull = True/Flase

# 查询用户名不为空的数据
Student.objects.filter(username__isnull=False)

# 查询用户名为空的数据
Student.objects.filter(username__isnull=True)

在操作数据的时候字段名是字符串类型的解决方法


在日常开发中经常会获取到字符串类型的字段名,且需要通过该字符串类型的字段名去操作数据

1. 添加数据

dic = {'username': 'Kevin'}

Student.objects.create(**dic)

2. 修改数据

dic = {'name': 'Aimer'}

objs = Student.objects.filter(id=4)

objs.update(**dic)

3. 查询数据

  • 方法一 -> 通过 values 或 values_list

Student.objects.values('id', 'name')

Student.objects.values_list('id', 'name')

  • 方法二 -> 使用动态实参的方法

dic = {
    'id__gt': 3
}
data = Student.objects.filter(**dic)

  • 查询所有数据

dic = {}
data = Student.objects.filter(**dic)